package cn.com.easy.pay.alipay.www.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.com.easy.exception.BusinessException;
import cn.com.easy.pay.alipay.www.config.AlipayConfig;
import cn.com.easy.pay.alipay.www.util.AlipaySubmit;
import cn.com.easy.utils.HttpClientUtils;

import com.google.common.collect.Lists;

/**
 * 无密退款的基础控制器
 * 
 * @author nibili 2017年4月10日
 * 
 */
public abstract class AlipayRefundByNoPwdBaseController {

	private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";

	/**
	 * 业务参数
	 * 
	 * @return
	 * @author nibili 2017年4月6日
	 */
	public abstract AlipayRefundParam getAlipayRefundParam(HttpServletRequest httpRequest) throws BusinessException;

	/**
	 * 系统参数
	 * 
	 * @return
	 * @author nibili 2017年4月6日
	 */
	public abstract AlipayConfig getAlipayConfig(HttpServletRequest httpRequest) throws BusinessException;

	/**
	 * 静默请求回调方法，可以 sleep(5000),静默5秒再返回，以便支付宝回调确认
	 * 
	 * @param httpServletRequest
	 * @param httpResponse
	 * @author nibili 2017年4月10日
	 */
	public abstract void noReturnCallBack(HttpServletRequest httpServletRequest, HttpServletResponse httpResponse) throws BusinessException;

	/**
	 * 自动跳转到有密退款页面
	 * 
	 * @param httpServletRequest
	 * @param httpResponse
	 * @author nibili 2017年4月7日
	 * @throws Exception
	 */
	@RequestMapping("/refund/by/no/pwd.html")
	public void requestRefundByNoPwdAndNoReturn(HttpServletRequest httpServletRequest, HttpServletResponse httpResponse) throws Exception {

		AlipayConfig alipayConfig = getAlipayConfig(httpServletRequest);
		AlipayRefundParam alipayRefundParam = getAlipayRefundParam(httpServletRequest);

		// 无密退款
		alipayConfig.setService(AlipayConfig.SERVICE_REFUND_NO_PWD);
		// //////////////////////////////////请求参数//////////////////////////////////////

		// 把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("service", alipayConfig.getService());
		sParaTemp.put("partner", alipayConfig.getPartner());
		sParaTemp.put("_input_charset", alipayConfig.getInput_charset());
		sParaTemp.put("notify_url", alipayConfig.getNotify_url());
		sParaTemp.put("refund_date", alipayConfig.getRefund_date());
		sParaTemp.put("batch_no", alipayRefundParam.getBatch_no());
		sParaTemp.put("batch_num", alipayRefundParam.getBatch_num());
		sParaTemp.put("detail_data", alipayRefundParam.getDetail_data());
		//
		HttpClientUtils.get(ALIPAY_GATEWAY_NEW, AlipaySubmit.buildRequestPara(sParaTemp, alipayConfig));
		// 静默请求回调
		noReturnCallBack(httpServletRequest, httpResponse);

	}

	/**
	 * 自动跳转到有密退款页面
	 * 
	 * @param httpServletRequest
	 * @param httpResponse
	 * @throws IOException
	 * @author nibili 2017年4月7日
	 * @throws BusinessException
	 */
	@RequestMapping("/refund/by/no/pwd.html")
	public void requestRefundByNoPwd(HttpServletRequest httpServletRequest, HttpServletResponse httpResponse) throws IOException, BusinessException {

		AlipayConfig alipayConfig = getAlipayConfig(httpServletRequest);
		AlipayRefundParam alipayRefundParam = getAlipayRefundParam(httpServletRequest);

		// 无密退款
		alipayConfig.setService(AlipayConfig.SERVICE_REFUND_NO_PWD);
		// //////////////////////////////////请求参数//////////////////////////////////////

		// 把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("service", alipayConfig.getService());
		sParaTemp.put("partner", alipayConfig.getPartner());
		sParaTemp.put("_input_charset", alipayConfig.getInput_charset());
		sParaTemp.put("notify_url", alipayConfig.getNotify_url());
		sParaTemp.put("refund_date", alipayConfig.getRefund_date());
		sParaTemp.put("batch_no", alipayRefundParam.getBatch_no());
		sParaTemp.put("batch_num", alipayRefundParam.getBatch_num());
		sParaTemp.put("detail_data", alipayRefundParam.getDetail_data());

		// 建立请求
		String sHtmlText = AlipaySubmit.buildRequest(sParaTemp, "get", "确认", alipayConfig);
		httpResponse.setContentType("text/html;charset=" + alipayConfig.getInput_charset());
		httpResponse.getWriter().write(sHtmlText);// 直接将完整的表单html输出到页面
		httpResponse.getWriter().flush();
		httpResponse.getWriter().close();
	}

	/**
	 * 单笔数据
	 * 
	 * @author nibili 2017年4月1日
	 * 
	 */
	public static class AlipayRefundDetailDataParam {
		/** 支付宝交易号 */
		private String trade_no;
		/** 退款总金额 */
		private String total_fee;
		/** 退款理由 */
		private String body;

		/**
		 * get 支付宝交易号
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getTrade_no() {
			return trade_no;
		}

		/**
		 * set 支付宝交易号
		 * 
		 * @param trade_no
		 * @author nibili 2017年4月1日
		 */
		public void setTrade_no(String trade_no) {
			this.trade_no = trade_no;
		}

		/**
		 * get 退款总金额
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getTotal_fee() {
			return total_fee;
		}

		/**
		 * set 退款总金额
		 * 
		 * @param total_fee
		 * @author nibili 2017年4月1日
		 */
		public void setTotal_fee(String total_fee) {
			this.total_fee = total_fee;
		}

		/**
		 * get 退款理由
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getBody() {
			return body;
		}

		/**
		 * set 退款理由
		 * 
		 * @param body
		 * @author nibili 2017年4月1日
		 */
		public void setBody(String body) {
			this.body = body;
		}

	}

	/**
	 * 支付宝有密退款参数<br/>
	 * 具体参数 参看：https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.
	 * KNgYXT&treeId=62&articleId=104744&docType=1
	 * 
	 * @author nibili 2017年4月1日
	 * 
	 */
	public static class AlipayRefundParam {

		/**
		 * 退款批次号 ，每进行一次即时到账批量退款，都需要提供一个批次号，通过该批次号可以查询这一批次的退款交易记录，对于每一个合作伙伴，
		 * 传递的每一个批次号都必须保证唯一性。
		 * 
		 * 格式为：退款日期（8位）+流水号（3～24位）。
		 * 
		 * 不可重复，且退款日期必须是当天日期。流水号可以接受数字或英文字符，建议使用数字，但不可接受“000”。
		 */
		private String batch_no;
		/** 总笔数 */
		private String batch_num;
		/**
		 * 单笔数据集<br/>
		 * * 单笔数据集参数说明
		 * 
		 * 单笔数据集格式为：第一笔交易退款数据集#第二笔交易退款数据集#第三笔交易退款数据集…#第N笔交易退款数据集；
		 * 交易退款数据集的格式为：原付款支付宝交易号^退款总金额^退款理由； 不支持退分润功能。<br/>
		 * “退款理由”长度不能大于256字节，“退款理由”中不能有“^”、“|”、“$”、“#”等影响detail_data格式的特殊字符；
		 */
		private List<AlipayRefundDetailDataParam> detailDataList;

		/**
		 * get 单笔数据集<br/>
		 * 单笔数据集参数说明
		 * 
		 * 单笔数据集格式为：第一笔交易退款数据集#第二笔交易退款数据集#第三笔交易退款数据集…#第N笔交易退款数据集；
		 * 交易退款数据集的格式为：原付款支付宝交易号^退款总金额^退款理由； 不支持退分润功能。<br/>
		 * “退款理由”长度不能大于256字节，“退款理由”中不能有“^”、“|”、“$”、“#”等影响detail_data格式的特殊字符；
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getDetail_data() {
			if (CollectionUtils.isNotEmpty(detailDataList) == true) {
				List<String> detailDataStringList = Lists.newArrayList();
				for (AlipayRefundDetailDataParam alipayRefundDetailDataParam : detailDataList) {
					// “退款理由”长度不能大于256字节，“退款理由”中不能有“^”、“|”、“$”、“#”等影响detail_data格式的特殊字符；
					String body = alipayRefundDetailDataParam.getBody().replaceAll("[\\^|\\||\\$|\\#]", ";");
					String detail_data = alipayRefundDetailDataParam.getTrade_no() + "^" + alipayRefundDetailDataParam.getTotal_fee() + "^" + body;
					detailDataStringList.add(detail_data);
				}
				// 单笔数据集格式为：第一笔交易退款数据集#第二笔交易退款数据集#第三笔交易退款数据集…#第N笔交易退款数据集；
				return StringUtils.join(detailDataStringList, "#");
			} else {
				return "";
			}
		}

		/**
		 * get 退款批次号<br/ >
		 * * 退款批次号 ，每进行一次即时到账批量退款，都需要提供一个批次号，通过该批次号可以查询这一批次的退款交易记录，对于每一个合作伙伴，
		 * 传递的每一个批次号都必须保证唯一性。
		 * 
		 * 格式为：退款日期（8位）+流水号（3～24位）。
		 * 
		 * 不可重复，且退款日期必须是当天日期。流水号可以接受数字或英文字符，建议使用数字，但不可接受“000”。
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getBatch_no() {
			return batch_no;
		}

		/**
		 * set 退款批次号<br/>
		 * * 退款批次号 ，每进行一次即时到账批量退款，都需要提供一个批次号，通过该批次号可以查询这一批次的退款交易记录，对于每一个合作伙伴，
		 * 传递的每一个批次号都必须保证唯一性。
		 * 
		 * 格式为：退款日期（8位）+流水号（3～24位）。
		 * 
		 * 不可重复，且退款日期必须是当天日期。流水号可以接受数字或英文字符，建议使用数字，但不可接受“000”。
		 * 
		 * @param batch_no
		 * @author nibili 2017年4月1日
		 */
		public void setBatch_no(String batch_no) {
			this.batch_no = batch_no;
		}

		/**
		 * get 总笔数
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public String getBatch_num() {
			return batch_num;
		}

		/**
		 * set 总笔数
		 * 
		 * @param batch_num
		 * @author nibili 2017年4月1日
		 */
		public void setBatch_num(String batch_num) {
			this.batch_num = batch_num;
		}

		/**
		 * get 单笔数据集
		 * 
		 * @return
		 * @author nibili 2017年4月1日
		 */
		public List<AlipayRefundDetailDataParam> getDetailDataList() {
			return detailDataList;
		}

		/**
		 * set 单笔数据集<br/>
		 * * 单笔数据集参数说明
		 * 
		 * 单笔数据集格式为：第一笔交易退款数据集#第二笔交易退款数据集#第三笔交易退款数据集…#第N笔交易退款数据集；
		 * 交易退款数据集的格式为：原付款支付宝交易号^退款总金额^退款理由； 不支持退分润功能。<br/>
		 * “退款理由”长度不能大于256字节，“退款理由”中不能有“^”、“|”、“$”、“#”等影响detail_data格式的特殊字符；
		 * 
		 * @param detailDataList
		 * @author nibili 2017年4月1日
		 */
		public void setDetailDataList(List<AlipayRefundDetailDataParam> detailDataList) {
			this.detailDataList = detailDataList;
		}

	}

}
